#coding:utf8
import traceback
import json
import re
import comm
from data import ch2rdb 
from comm import get_tree_struct, SentenceTree, segword, get_str
from transduction import tree_transformer
from score_judge import grammar_calculator, Judger

class Analyser:
    def __init__(self):
        self.raw_patterns = None
        self.raw_interrog_words = None
        self.grammar_judge = Judger(grammar_calculator)

    @property
    def patterns(self):
        if not self.raw_patterns:
            self.raw_patterns = ch2rdb.load_patterns()
        return self.raw_patterns

    @property
    def interrog_words(self):
        if not self.raw_interrog_words:
            self.raw_interrog_words = self._load_interrog_words()
        return self.raw_interrog_words

    def _load_interrog_words(self):
        res = set()
        for pattern in self.patterns:
            for interrog_pattern in pattern[2]:
                res.add(interrog_pattern)
        return res

    def _interrog_level(self, pattern):
        if '.+' in pattern:
            return 0
        elif '$' in pattern:
            return 1
        elif len(pattern) == 3 and pattern[-1] == pattern[0] == '.':
            return 2
        else:
            return 3

    @comm.unique_resp
    def get_interrog_words(self, sentence, interrog_patterns = None):
        res = []
        interrog_patterns = interrog_patterns or self.interrog_words
        sorted_patterns = [[] for x in range(4)]
        for pattern in interrog_patterns:
            sorted_patterns[self._interrog_level(pattern)].append(pattern)

        #是.+还是.+, 结构
        for pattern in sorted_patterns[0]:
            match = re.search(pattern, sentence)
            if match:
                words = [ x for x in pattern.split('.+') if x ]
                off = 0
                for word in words:
                    off = sentence.find(word, off)
                    res.append((sentence[off : off + len(word)], off, off + len(word)))
                    off += len(word)
        if res: return res

        #.没$, .不$
        for pattern in sorted_patterns[1]:
            match = re.search(pattern, sentence)
            if match:
                forward = re.search(u"需要|有|是|可以|会", sentence)
                if forward:
                    res.append((forward.group(), forward.start(), forward.end()))
                off =  match.start()
                res.append((match.group()[0], off, off + 1))
        if res: return res

        # .没.，.不.
        for pattern in sorted_patterns[2]:
            for one_match in re.finditer(pattern, sentence):
                for length in range(2, 0, -1):
                    right = one_match.end() - 1
                    if right + length > len(sentence): continue
                    word = sentence[right : right + length]
                    left = sentence.find(word, 0, right)
                    if left == -1: continue
                    if left + length == right - 1:
                        res.append((sentence[left : right + length], left, right + length))
                    else:
                        res.append((sentence[left : left + length], left, left + length))
                        res.append((sentence[right - 1 : right + length], right - 1, right + length))
                    break
        if res: return res

        #怎么、什么、多少
        for pattern in sorted_patterns[3]:
            match = re.search(pattern, sentence)
            if match:
                res.append((match.group(), match.start(), match.end()))
        return res


    def _remark_interrog_words(self, words_grammar, interrog_words, words_combine=True):
        if not interrog_words: return words_grammar
        res = []
        start = 0
        for word, tag in words_grammar:
            end = start + len(word)
            for interrog_word in interrog_words:
                if interrog_word[1] <= start < interrog_word[2] or \
                   interrog_word[1] < end <= interrog_word[2]:
                    res.append((word, u'~'))
                    break
            else:
                res.append((word, tag))
            start = end
        if not words_combine:
            return res

        tres = []
        flag = False
        for word, tag in res:
            if tag == u'~':
                if flag:
                    tres[-1][0] += word
                else:
                    flag = True
                    tres.append([word, tag])
            else:
                flag = False
                tres.append((word, tag))
        return tres

    def _match_sentence_struct(self, grammar, max_result):
        sentence = ''.join([x[0] for x in grammar])
        interrog_words = self.get_interrog_words(sentence)
        grammar = self._remark_interrog_words(grammar, interrog_words)
        res = [(self.grammar_judge.get_score(grammar, pattern[3]), pattern) 
                for pattern in self.patterns]
        res.sort(reverse=True)
        return res[:max_result]

    def match_sentence_struct(self, sentence, max_result):
        segword_result = json.loads(segword(sentence))
        grammar = [ (x['word'], x['word_std_tag'] or x['word_tag']) for x in segword_result ]
        return self._match_sentence_struct(grammar, max_result)

    def match_interrog_pattern(self, sentence, max_result):
        if isinstance(sentence, SentenceTree):
            sentence_tree = sentence
            sentence = sentence_tree.to_sentence()
            struct_scores = self._match_sentence_struct(sentence_tree.get_grammar(), len(self.patterns))
        else:
            struct_scores = self.match_sentence_struct(sentence, len(self.patterns))
        res = []
        for grammar_score, pattern in struct_scores:
            interrog_score = 0
            if self.get_interrog_words(sentence, pattern[2]):
                interrog_score = 100
            res.append(((grammar_score * 0.5 + interrog_score * 0.5) * 1.3, pattern))

        res.sort(reverse=True)
        res = res[:max_result]
        return res

    def _sentence_with_interrog_words(self, origin_tree, short_tree):
        short_pos = [x['Pos'] for x in short_tree._get_leaves()]
        max_pos = -1
        for pos in short_pos:
            if pos < max_pos: #缩句后存在逆序,这种情况没法补疑问词
                return origin_tree.to_sentence()
            else:
                max_pos = pos
        grammar = origin_tree.get_grammar()
        interrog_words = self.get_interrog_words(origin_tree.to_sentence())
        grammar = self._remark_interrog_words(grammar, interrog_words, False)
        res = []
        for pos, word in enumerate(grammar):
            word, syntax = word
            if syntax == '~' or pos in short_pos:
                res.append(word)
        return ''.join(res)

    def analyse(self, sentence, max_result=3):
        sentence_tree = get_tree_struct(sentence)
        sentence_tree.mark_leaves_num()
        short_sentence_tree = tree_transformer.transform(sentence_tree)
        short_sentence = short_sentence_tree.to_sentence()
        if not self.get_interrog_words(short_sentence):
            short_sentence = self._sentence_with_interrog_words(sentence_tree, short_sentence_tree)
        interrog_pattern = self.match_interrog_pattern(short_sentence, max_result)
        return interrog_pattern


analyser = Analyser()
del Analyser

if __name__ == '__main__':
    import sys
    from data import ch2rdb
    reload(sys)
    sys.setdefaultencoding('utf8')

    sentences_data = ch2rdb.get_sentence_data()
    samples = [x[0][0] for x in sentences_data]

    comm.load_cache()
#    samples = [u'有没有款式好看些的手机？']
    for sample, pattern in zip(samples, ch2rdb.load_patterns()):
        print '-------------------------------------'
        print 'sentence:', sample
        print '  ----> '
        result = analyser.analyse(sample)
        for one in result:
            print get_str(one)
        #print get_str(result)
        #print json.dumps(result, ensure_ascii=False)
        print 'correct pattern:', get_str(pattern)

    comm.dump_cache()
